package com.xyht.sca_s.student_manage_system.modules.personnelManagement.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.PictureType;
import com.deepoove.poi.data.Pictures;
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.PictureUtil;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.common.constant.FileSavePathConstant;
import com.xyht.sca_s.student_manage_system.modules.commonExamine.entity.SmsCommonExaminePicEntity;
import com.xyht.sca_s.student_manage_system.modules.personnelManagement.entity.SmsContractManagement;
import com.xyht.sca_s.student_manage_system.modules.personnelManagement.entity.req.SmsContractManagementAddReq;
import com.xyht.sca_s.student_manage_system.modules.personnelManagement.entity.req.SmsContractManagementDeletedReq;
import com.xyht.sca_s.student_manage_system.modules.personnelManagement.entity.req.SmsContractManagementUpdateReq;
import com.xyht.sca_s.student_manage_system.modules.personnelManagement.entity.resp.SmsContractManagementDetailResp;
import com.xyht.sca_s.student_manage_system.modules.personnelManagement.entity.resp.SmsContractManagementListResp;
import com.xyht.sca_s.student_manage_system.modules.personnelManagement.mapper.SmsContractManagementMapper;
import com.xyht.sca_s.student_manage_system.modules.personnelManagement.service.SmsContractManagementService;
import com.xyht.sca_s.student_manage_system.modules.teacher.entity.SmsTeacherInfo;
import com.xyht.sca_s.student_manage_system.modules.teacher.mapper.SmsTeacherInfoMapper;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.commonExamine.constant.CommonConstant.IMG_MAX_HEIGHT;
import static com.xyht.sca_s.student_manage_system.modules.commonExamine.constant.CommonConstant.IMG_MAX_WIDTH;


/**
 * <p>
 * 合同管理 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2023-09-25
 */
@Service
public class SmsContractManagementServiceImpl extends ServiceImpl<SmsContractManagementMapper, SmsContractManagement> implements SmsContractManagementService {
    @Resource
    private FileSavePathConstant fileSavePathConstant;
    @Autowired
    private SmsContractManagementMapper contractManagementMapper;
    @Autowired
    private SmsTeacherInfoMapper teacherInfoMapper;
    @Autowired
    private PictureUtil pictureUtil;

    @Override
    public ResponseResult addContractManagement(SmsContractManagementAddReq addReq) {
        if(isNullOrEmpty(addReq.getTchId(),addReq.getStartDate(),addReq.getEndDate(),addReq.getSignYear(),addReq.getContract())){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        Date startDate = TimeUtil.StringtoDate(addReq.getStartDate());
        Date endDate = TimeUtil.StringtoDate(addReq.getEndDate());
        SmsTeacherInfo teacherInfo = teacherInfoMapper.selectById(addReq.getTchId());
        if(isNullOrEmpty(teacherInfo)){
            return CommonResult.failed(CommonCodeEnum.TEACHER_NOT_EXIST);
        }
        List<SmsContractManagement> smsContractManagements = contractManagementMapper.selectList(new LambdaQueryWrapper<SmsContractManagement>()
                .eq(SmsContractManagement::getTchId, addReq.getTchId()));
        //新更合同信息
        if(smsContractManagements != null && smsContractManagements.size() > 0){
            SmsContractManagement smsContractManagement = smsContractManagements.get(0);
            String tchId = smsContractManagement.getTchId();
            if(tchId.equals(addReq.getTchId())){
                SmsContractManagement updateContractManagement = new SmsContractManagement();
                BeanUtils.copyProperties(addReq,updateContractManagement);
                updateContractManagement.setStartDate(startDate);
                updateContractManagement.setEndDate(endDate);
                updateContractManagement.setContract(addReq.getContract());
                contractManagementMapper.update(updateContractManagement,new LambdaQueryWrapper<SmsContractManagement>()
                .eq(SmsContractManagement::getTchId,addReq.getTchId()));

            }
        }else {
            //插入合同信息
            SmsContractManagement addContractManagement = new SmsContractManagement();
            BeanUtils.copyProperties(addReq, addContractManagement);
            addContractManagement.setStartDate(startDate);
            addContractManagement.setEndDate(endDate);
            addContractManagement.setContract(addReq.getContract());
            contractManagementMapper.insert(addContractManagement);
        }
        return CommonResult.success();
    }

    @Override
    public ResponseResult getContractManagementList(Integer pageNum, Integer pageSize, String tchName) {
        Page<SmsTeacherInfo> page = new Page<>(pageNum,pageSize);
        LambdaQueryWrapper<SmsTeacherInfo> queryWrapper = new LambdaQueryWrapper<>();
        if(!isNullOrEmpty(tchName)){
            queryWrapper.like(SmsTeacherInfo::getTchName,tchName);
        }
        teacherInfoMapper.selectPage(page,queryWrapper);
        List<SmsContractManagementListResp> contractManagementList = new ArrayList<>();
        contractManagementList = page.getRecords()
                .stream()
                .map(smsTeacherInfo -> {
                    SmsContractManagementListResp contractManagementResp = new SmsContractManagementListResp();
                    //教师信息
                    BeanUtils.copyProperties(smsTeacherInfo,contractManagementResp);
                    contractManagementResp.setTchId(smsTeacherInfo.getId());
                    List<SmsContractManagement> smsContractManagements = contractManagementMapper.selectList(new LambdaQueryWrapper<SmsContractManagement>()
                            .eq(SmsContractManagement::getTchId, smsTeacherInfo.getId()));
                    if(smsContractManagements != null && smsContractManagements.size() > 0){
                        SmsContractManagement smsContractManagement = smsContractManagements.get(0);
                        //合同信息
                        BeanUtils.copyProperties(smsContractManagement,contractManagementResp);
//                        String contract = smsContractManagement.getContract();
//                        List<String> contractList = JSONObject.parseArray(contract, String.class);
//                        contractManagementResp.setContract(contractList);
                        contractManagementResp.setContractId(smsContractManagement.getId());
                    }
                    return contractManagementResp;
                })
                .collect(Collectors.toList());
        int total = (int)page.getTotal();
        return CommonResult.success(contractManagementList,total);
    }

    @Override
    public ResponseResult getContractManagementDetail(String id) {
        if(isNullOrEmpty(id)){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        SmsContractManagement smsContractManagement = contractManagementMapper.selectById(id);
        if(isNullOrEmpty(smsContractManagement)){
            return CommonResult.failed(CommonCodeEnum.CONTRACT_NOT_EXIST);
        }
        SmsContractManagementDetailResp contractManagementDetailResp = new SmsContractManagementDetailResp();
        BeanUtils.copyProperties(smsContractManagement,contractManagementDetailResp);
        contractManagementDetailResp.setContractId(smsContractManagement.getId());
//        String contract = smsContractManagement.getContract();
//        List<String> contractList = JSONObject.parseArray(contract, String.class);
//        contractManagementDetailResp.setContract(contractList);
        return CommonResult.success(contractManagementDetailResp);
    }

    @Override
    public ResponseResult updateContractManagement(SmsContractManagementUpdateReq updateReq) {
        if(isNullOrEmpty(updateReq.getContractId(),updateReq.getTchId(),updateReq.getContract(),updateReq.getEndDate()
                ,updateReq.getStartDate(),updateReq.getSignYear())){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        Date startDate = TimeUtil.StringtoDate(updateReq.getStartDate());
        Date endDate = TimeUtil.StringtoDate(updateReq.getEndDate());
        SmsContractManagement smsContractManagement = contractManagementMapper.selectOne(new LambdaQueryWrapper<SmsContractManagement>()
                .eq(SmsContractManagement::getId, updateReq.getContractId())
                .eq(SmsContractManagement::getTchId, updateReq.getTchId()));
        if(isNullOrEmpty(smsContractManagement)){
            return CommonResult.failed(CommonCodeEnum.CONTRACT_NOT_EXIST);
        }
        BeanUtils.copyProperties(updateReq,smsContractManagement);

//        List<String> contractList = updateReq.getContractList();
        smsContractManagement.setContract(updateReq.getContract());
        smsContractManagement.setStartDate(startDate);
        smsContractManagement.setEndDate(endDate);
        contractManagementMapper.updateById(smsContractManagement);
        return CommonResult.success();
    }

    @Override
    public ResponseResult deletedContractManagement(SmsContractManagementDeletedReq deletedReq) {
        if(isNullOrEmpty(deletedReq.getTchId(),deletedReq.getContractId())){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        SmsContractManagement smsContractManagement = contractManagementMapper.selectOne(new LambdaQueryWrapper<SmsContractManagement>()
                .eq(SmsContractManagement::getId, deletedReq.getContractId())
                .eq(SmsContractManagement::getTchId, deletedReq.getTchId()));
        if(isNullOrEmpty(smsContractManagement)){
            return CommonResult.failed(CommonCodeEnum.CONTRACT_NOT_EXIST);
        }
        contractManagementMapper.deleteById(deletedReq.getContractId());
        return CommonResult.success();
    }

    @Override
    @Async
    public Future<ResponseResult> tableDownload(String contractId, HttpServletResponse response) {
        SmsContractManagement smsContractManagement = contractManagementMapper.selectById(contractId);
        if (smsContractManagement == null || smsContractManagement.getId() == null) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.CONTRACT_NOT_EXIST));
        }

        String tchId = smsContractManagement.getTchId();
        SmsTeacherInfo teacherInfo = teacherInfoMapper.selectById(tchId);
        if (!isNullOrEmpty(teacherInfo)) {
            String tchName = teacherInfo.getTchName();
            String OSName = System.getProperty("os.name");
            String filePath = OSName.toLowerCase().startsWith("win") ? fileSavePathConstant.getFILE_DOWNLOAD_PATH()
                    : fileSavePathConstant.getFILE_DOWNLOAD_PATH_LINUX();

            String newFilePath = filePath + contractId + ".docx";
            String pdfFilePath = filePath + contractId + ".pdf";

            File pdfFile = new File(pdfFilePath);

            try {
                Map<String, Object> map = new HashMap<>();

                map.put("name", filterResultNull(tchName));

                //封装图片
                List<Map<String, Object>> picList = new ArrayList<>();
                if (!isNullOrEmpty(smsContractManagement.getContract())) {
                    List<SmsCommonExaminePicEntity> examinePicEntityList = JSONObject.parseArray(
                            smsContractManagement.getContract(), SmsCommonExaminePicEntity.class);
                    if (examinePicEntityList != null && examinePicEntityList.size() > 0) {
                        for (SmsCommonExaminePicEntity picEntity : examinePicEntityList) {
                            String[] splitStr = picEntity.getUrl().split("=");
                            String fileName = splitStr[splitStr.length - 1];

                            String[] splitType = fileName.split("u002E");
                            String type = splitType[splitType.length - 1];
                            PictureType pictureType = pictureUtil.getPictureType(type);

                            File picture = new File(filePath + fileName);
                            BufferedImage sourceImg = ImageIO.read(picture);
                            Integer width = sourceImg.getWidth();
                            Integer height = sourceImg.getHeight();
                            if ((width * 1.0) / IMG_MAX_WIDTH < (height * 1.0) / IMG_MAX_HEIGHT) {
                                if (width > IMG_MAX_WIDTH) {
                                    height = Integer.parseInt(new java.text.DecimalFormat("0").format(height * IMG_MAX_WIDTH / (width * 1.0)));
                                }
                                if (height > IMG_MAX_HEIGHT) {
                                    width = Integer.parseInt(new java.text.DecimalFormat("0").format(width * IMG_MAX_HEIGHT / (height * 1.0)));
                                }
                            } else {
                                if (height > IMG_MAX_HEIGHT) {
                                    width = Integer.parseInt(new java.text.DecimalFormat("0").format(width * IMG_MAX_HEIGHT / (height * 1.0)));
                                }
                                if (width > IMG_MAX_WIDTH) {
                                    height = Integer.parseInt(new java.text.DecimalFormat("0").format(height * IMG_MAX_WIDTH / (width * 1.0)));
                                }
                            }

                            File file = new File(filePath + fileName);
                            if (file.exists()) {
                                InputStream inputStream = new FileInputStream(file);
                                PictureRenderData pictures = Pictures.ofStream(inputStream,
                                        pictureType).size(width, height)
                                        .create();

                                Map<String, Object> picMap = new HashMap<>();
                                picMap.put("contract", pictures);
                                picList.add(picMap);
                            }
                        }
                    }
                    if (picList.size() > 0) {
                        map.put("contractList", picList);
                    }
                }

                ClassPathResource resource = new ClassPathResource("applyTemplates/contractManagementTemplate.docx");
                InputStream is = resource.getInputStream();
                FileOutputStream outputStream = new FileOutputStream(newFilePath);
                XWPFTemplate template = XWPFTemplate.compile(is);

                //配置图片标签
//            Configure config = template.getConfig();
//            for (String tag:picTagList
//            ) {
//                config.customPolicy(tag,new PictureRenderPolicy());
//            }
                template.render(map);

                template.write(outputStream);

                is.close();
                outputStream.close();
                template.close();

                //word转pdf
                File destOri = new File(newFilePath);
                FileInputStream fileInputStream = new FileInputStream(destOri);
                FileOutputStream fileOutputStream = new FileOutputStream(pdfFilePath);

                Document document = new Document();
                document.loadFromStream(fileInputStream, FileFormat.Docx);
                //保存为PDF
                document.saveToFile(pdfFilePath, FileFormat.PDF);


                fileInputStream.close();
                fileOutputStream.close();
                document.close();

                log.debug("文件生成完成!");
            } catch (Exception e) {
                e.printStackTrace();
                return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
            }

            try {
                // 加载PDF文档
                PDDocument doc = PDDocument.load(pdfFile);
                doc.setAllSecurityToBeRemoved(true);
                // 创建水印
                String watermark = "南充电影工业职业学院";
                PDPageContentStream contentStream;

                for (PDPage page : doc.getPages()) {
                    contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true);

                    //加载字体
                    ClassPathResource resource = new ClassPathResource("fonts/123.ttf");
                    InputStream is = resource.getInputStream();
                    PDFont font = PDType0Font.load(doc, is);


                    int startX = 0; // 起始位置 x 坐标
                    int startY = 0; // 起始位置 y 坐标
                    float angle = -45; // 角度
                    float interval = 220; // 间隔
                    float opacity = 0.3f; // 透明度
                    int colorR = 127; // 颜色 red 值
                    int colorG = 127; // 颜色 green 值
                    int colorB = 127; // 颜色 blue 值

                    //透明的
                    PDExtendedGraphicsState r0 = new PDExtendedGraphicsState();
                    r0.setNonStrokingAlphaConstant(opacity);
                    r0.setAlphaSourceFlag(true);
                    contentStream.setGraphicsStateParameters(r0);

                    //水印颜色
                    contentStream.setNonStrokingColor(colorR, colorG, colorB);
                    contentStream.beginText();
                    contentStream.setFont(font, 30f);

                    Integer x_times = (int) Math.ceil(page.getMediaBox().getWidth() / interval);
                    Integer y_times = (int) Math.ceil(page.getMediaBox().getHeight() / interval);
                    for (int x = startX; x <= x_times; x++) {
                        for (int y = startY; y <= y_times; y++) {
                            contentStream.setTextRotation(angle, (x * interval), (y * interval));
                            contentStream.showText(watermark);
                        }
                    }
                    contentStream.endText();
                    contentStream.restoreGraphicsState();
                    contentStream.close();
                    is.close();
                }


                response.setCharacterEncoding("utf-8");
                response.setContentType("application/vnd.pdf;charset=utf-8");
                response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(tchName + "的合同表预览.pdf", "utf-8"));
                response.setHeader("file-name", URLEncoder.encode(tchName + "的合同表预览.pdf", "utf-8"));
                response.setHeader("file-type", "download");
                response.setHeader("Access-Control-Expose-Headers", "file-type,file-name");

                //刷新缓冲
                response.flushBuffer();
                // 保存PDF文档
                doc.save(response.getOutputStream());
                doc.close();
            } catch (Exception e) {
                e.printStackTrace();
                return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
            }
        }
        return null;
    }
    private String filterResultNull(String resultStr) {
        if (resultStr == null || resultStr.equals("null")) {
            return "";
        }
        return resultStr;
    }
}

